package com.zjdiepu.www.security.sign.rsa;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zjdiepu.www.config.ClientConfig;
import com.zjdiepu.www.config.ServerConfig;
import com.zjdiepu.www.security.encode.base64.Base64;
import com.zjdiepu.www.security.encode.rsa.RsaEncrypt;
import com.zjdiepu.www.security.server.core.Partners;
/**
 * 类描述: Rsa签名 <br/>     
 * 项目名称:zjdiepu-client <br/> 
 * 类名称:RsaProvider <br/>     
 * 创建人:xiongxiaotun <br/> 
 * 创建时间:2017年8月15日 下午3:31:03  <br/>   
 * 修改人:xiongxiaotun <br/> 
 * 修改时间: 2017年8月15日 下午3:31:03   <br/>  
 * 修改备注:   <br/> 
 * @version V1.0   <br/>
 */
public class RsaProvider {
    
	private static final Logger logger = LoggerFactory.getLogger(RsaProvider.class);
	/**
     * RSA最大加密明文大小 512 / 8 = 64 - 11 = 53  1024 / 8 = 128 - 11 = 117
     */  
    private static final int MAX_ENCRYPT_BLOCK = (RsaEncrypt.KEY_SIZE / 8 ) - 11; 
    
    /** *//** 
     * RSA最大解密密文大小 512 / 8 = 64  1024 / 8 = 128
     */  
    private static final int MAX_DECRYPT_BLOCK = RsaEncrypt.KEY_SIZE / 8;  
	/** 
     * rsa签名
     * @param plainTextData  明文数据 
     * @param publicKey 公钥
     * @return 密文
     */  
    public static String signWithPub(String plainTextData, String publicKey) {
    	if(StringUtils.isBlank(plainTextData)) {
			return null;
		}
    	//公钥签名
    	PublicKey publicKey_ = RsaEncrypt.loadPublicKeyByStr(publicKey);
        Cipher cipher = null;  
        try ( ByteArrayOutputStream out = new ByteArrayOutputStream(); ){  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey_);  
            byte[] data = plainTextData.getBytes("UTF-8");  
            int inputLen = data.length;  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段签名  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            } 
            byte[] encryptedData = out.toByteArray();  
            return Base64.encode(encryptedData);
        } catch (Exception e) {  
        	logger.error("公钥签名过程:plainTextData:{},异常栈:{}", new String(plainTextData), e);
        } 
        return null;
    }
    
    
    
    /**
   	* rsa验签
   	* @param content 密文
   	* @param privateKey 私钥
   	* @param partner 合作伙伴
   	* @return 明文
   	*/
   	public static String deSignWithPri(String content, Partners partner){
   		if(StringUtils.isBlank(content)) {
   			return null;
   		}
   		//碟普私钥解密
   		PrivateKey privateKey = RsaEncrypt.loadPrivateKeyByStr(ServerConfig.getPartnerRsaPrivateKey(partner));

        ByteArrayOutputStream writer;
   		try {
   			Cipher cipher = Cipher.getInstance("RSA");
   			cipher.init(Cipher.DECRYPT_MODE, privateKey);
   			//JSON对java String 类型会多出引号
   			if(content.startsWith("\"")){
   				content = content.substring(1);
   			}
   			if(content.endsWith("\"")) {
   				content = content.substring(0, content.length() - 1);
   			}
   			byte[] decode = Base64.decode(content);
   			InputStream ins = new ByteArrayInputStream(decode);
   			writer = new ByteArrayOutputStream();
   			//rsa解密的字节大小最多是128，将需要解密的内容，按128位拆开解密
   			byte[] buf = new byte[MAX_DECRYPT_BLOCK];
   			int bufl;

   			while ((bufl = ins.read(buf)) != -1) {
   			    byte[] block = null;

   			    if (buf.length == bufl) {
   			        block = buf;
   			    } else {
   			        block = new byte[bufl];
   			        for (int i = 0; i < bufl; i++) {
   			            block[i] = buf[i];
   			        }
   			    }

   			    writer.write(cipher.doFinal(block));
   			}
   			return new String(writer.toByteArray(),"UTF-8");
   		} catch (Exception e) {
   			logger.error("私钥解密过程  :cipherData:{}.异常栈:{}", content, partner.getCode(), e);
   		}
   		return null;
       }
   	/** 
     * rsa签名
     * @param plainTextData  明文数据 
     * @param privateKey 私钥
     * @return 密文
     */  
    public static String signWithPri(String plainTextData, String privateKey) {
    	if(StringUtils.isBlank(plainTextData)) {
			return null;
		}
    	//公钥签名
    	PrivateKey privateKey_ = RsaEncrypt.loadPrivateKeyByStr(privateKey);
        Cipher cipher = null;  
        try ( ByteArrayOutputStream out = new ByteArrayOutputStream(); ){  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, privateKey_);  
            byte[] data = plainTextData.getBytes("UTF-8");  
            int inputLen = data.length;  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段签名  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            } 
            byte[] encryptedData = out.toByteArray();  
            return Base64.encode(encryptedData);
        } catch (Exception e) {  
        	logger.error("公钥签名过程:plainTextData:{},异常栈:{}", new String(plainTextData), e);
        } 
        return null;
    }
    
    
    
    /**
   	* rsa验签
   	* @param content 密文
   	* @param partner 合作伙伴
   	* @return 明文
   	*/
   	public static String deSignWithPub(String content, Partners partner){
   		if(StringUtils.isBlank(content)) {
   			return null;
   		}
   		PublicKey publicKey = RsaEncrypt.loadPublicKeyByStr(ClientConfig.getPartnerRsaPublicKey(partner));

        ByteArrayOutputStream writer;
   		try {
   			Cipher cipher = Cipher.getInstance("RSA");
   			cipher.init(Cipher.DECRYPT_MODE, publicKey);
   			//JSON对java String 类型会多出引号
   			if(content.startsWith("\"")){
   				content = content.substring(1);
   			}
   			if(content.endsWith("\"")) {
   				content = content.substring(0, content.length() - 1);
   			}
   			byte[] decode = Base64.decode(content);
   			InputStream ins = new ByteArrayInputStream(decode);
   			writer = new ByteArrayOutputStream();
   			//rsa解密的字节大小最多是128，将需要解密的内容，按128位拆开解密
   			byte[] buf = new byte[MAX_DECRYPT_BLOCK];
   			int bufl;

   			while ((bufl = ins.read(buf)) != -1) {
   			    byte[] block = null;

   			    if (buf.length == bufl) {
   			        block = buf;
   			    } else {
   			        block = new byte[bufl];
   			        for (int i = 0; i < bufl; i++) {
   			            block[i] = buf[i];
   			        }
   			    }

   			    writer.write(cipher.doFinal(block));
   			}
   			return new String(writer.toByteArray(),"UTF-8");
   		} catch (Exception e) {
   			logger.error("私钥解密过程  :cipherData:{}.异常栈:{}", content, partner.getCode(), e);
   		}
   		return null;
       }
}
